/*
 * Copyright (c)  2018, XiQiao
 * All rights reserved. 
 *
 * Id:ExcelXlsxWriter.java   2018-07-26 22:41 wanglijun
 */
package io.marmot.poi.writer;

import io.marmot.poi.converter.WriteConverter;
import io.marmot.poi.domain.ExcelMapping;
import io.marmot.poi.domain.ExcelProperty;
import io.marmot.poi.exception.ExcelException;
import io.marmot.poi.util.DateUtils;
import io.marmot.poi.util.ExcelUtil;
import io.marmot.poi.util.ValidatorUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.*;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;

import java.text.ParseException;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * Title:
 * </p>
 * <p>
 * Description:
 * </p>
 * <p>
 * Copyright: Copyright (c) 2018
 * </p>
 * <p>
 * Company: XiQiao
 * </p>
 *
 * @author: wanglijun
 * @create: 2018-07-26 22:41
 * @version：1.0
 */
public class ExcelWriter {

    private ExcelMapping excelMapping;


    private Integer maxSheetRecords=5000;


    private CellStyle headerCellStyle = null;

    public ExcelWriter(ExcelMapping excelMapping){
        this.excelMapping=excelMapping;
    }

    public ExcelWriter(ExcelMapping excelMapping,Integer maxSheetRecords){
        this.excelMapping=excelMapping;
        this.maxSheetRecords=maxSheetRecords;
    }

    /***
     *
     * @param data
     * @param template
     * @return
     */
    public SXSSFWorkbook generateWorkbook(List<?> data, Boolean template) {
        SXSSFWorkbook workbook= ExcelUtil.newWorkbook ();
        List<ExcelProperty> propertyList=this.excelMapping.getPropertyList ();
        if(template){
            SXSSFSheet sheet = generateHeader(workbook, propertyList, this.excelMapping.getName(),this.excelMapping.getTitle (),true);
            if (null != data && data.size() > 0) {
                for (int i = 1; i <= data.size(); i++) {
                    SXSSFRow bodyRow = ExcelUtil.newRow(sheet, i);
                    for (int j = 0; j < propertyList.size(); j++) {
                        SXSSFCell cell = ExcelUtil.newCell(bodyRow, j);
                        buildCellValueByExcelProperty(cell, data.get(i - 1), propertyList.get(j));
                    }
                }
            }
        }else{
            double sheetNo = Math.ceil(data.size() / maxSheetRecords);
            for (int index = 0; index <= (sheetNo == 0.0 ? sheetNo : sheetNo - 1); index++) {
                String sheetName = excelMapping.getName() + (index == 0 ? "" : "_" + index);
                SXSSFSheet sheet = generateHeader(workbook, propertyList, sheetName,this.excelMapping.getTitle (), false);
                if (null != data && data.size() > 0) {
                    int startNo = index * maxSheetRecords;
                    int endNo = Math.min(startNo + maxSheetRecords, data.size());
                    for (int i = startNo; i < endNo; i++) {
                        SXSSFRow bodyRow = ExcelUtil.newRow(sheet, i + 1 - startNo);
                        for (int j = 0; j < propertyList.size(); j++) {
                            SXSSFCell cell = ExcelUtil.newCell(bodyRow, j);
                            buildCellValueByExcelProperty(cell, data.get(i), propertyList.get(j));
                        }
                    }
                }
            }
        }
        return workbook;
    }


    private void buildCellValueByExcelProperty(SXSSFCell cell, Object entity, ExcelProperty property) {
        Object cellValue;
        try {
            cellValue = BeanUtils.getProperty(entity, property.getName());
        } catch (Exception e) {
            throw new ExcelException (e);
        }
        if (null != cellValue) {
            String dateFormat = property.getDateFormat();
            if (!ValidatorUtil.isEmpty(dateFormat)) {
                if (cellValue instanceof Date) {
                    cell.setCellValue(DateUtils.format(dateFormat,(Date)cellValue));
                } else if (cellValue instanceof String) {
                    try {
                        Date parse = DateUtils.ENGLISH_LOCAL_DF.parse((String) cellValue);
                        cell.setCellValue(DateUtils.format(dateFormat, parse));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    return;
                }
            }
            // writeConverterExp && writeConverter
            String writeConverterExp = property.getWriteConverterExp();
            WriteConverter writeConverter = property.getWriteConverter();
            if (!ValidatorUtil.isEmpty(writeConverterExp)) {
                try {
                    cellValue = ExcelUtil.convertByExp(cellValue, writeConverterExp);
                } catch (Exception e) {
                    throw new ExcelException(e);
                }
            } else if (null != writeConverter) {
                cell.setCellValue(writeConverter.convert(cellValue));
                return;
            }
            cell.setCellValue(String.valueOf(cellValue));
        }
    }


    /***
     * @param workbook
     * @param propertyList
     * @param sheetName
     * @param title
     * @param tamplate
     * @return SXSSFSheet
     */
    private SXSSFSheet generateHeader(SXSSFWorkbook workbook, List<ExcelProperty> propertyList, String sheetName, String title, Boolean tamplate) {
        SXSSFDrawing drawing = null;
        SXSSFSheet sheet = ExcelUtil.newSheet(workbook, sheetName);
        SXSSFRow   headerRow=ExcelUtil.newRow (sheet,0);
        for (int i = 0; i < propertyList.size(); i++) {
            ExcelProperty property=propertyList.get (i);
            SXSSFCell cell=ExcelUtil.newCell (headerRow,i);
            ExcelUtil.setColumnWidth (sheet,i,property.getWidth (),property.getColumn ());
            if(tamplate){
                ExcelUtil.setColumnCellRange (sheet,property.getOptions (),1,maxSheetRecords,i,i);
                if(null==drawing){
                    drawing=sheet.createDrawingPatriarch ();
                }
                if(StringUtils.isNotEmpty (property.getComment ())){
                    Comment cellComment = drawing.createCellComment(//
                            new XSSFClientAnchor (0, 0, 0, 0, i, 0, i, 0));
                    XSSFRichTextString xssfRichTextString = new XSSFRichTextString(property.getComment());
                    Font commentFormatter = workbook.createFont();
                    xssfRichTextString.applyFont(commentFormatter);
                    cellComment.setString(xssfRichTextString);
                    cell.setCellComment(cellComment);
                }
            }
            cell.setCellStyle(getHeaderCellStyle(workbook));
            String headerColumnValue = property.getColumn();
            if (tamplate && null != property.getRequired() && property.getRequired()) {
                headerColumnValue = (headerColumnValue + "[*]");
            }
            cell.setCellValue(headerColumnValue);
        }
        return sheet;
    }

    /***
     * 设置
     * @param wb
     * @return
     */
    public CellStyle getHeaderCellStyle(SXSSFWorkbook wb) {
        if (null == headerCellStyle) {
            headerCellStyle = wb.createCellStyle();
            Font font = wb.createFont();
            headerCellStyle.setFillForegroundColor((short) 12);
            headerCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            headerCellStyle.setBorderTop(BorderStyle.DOTTED);
            headerCellStyle.setBorderRight(BorderStyle.DOTTED);
            headerCellStyle.setBorderBottom(BorderStyle.DOTTED);
            headerCellStyle.setBorderLeft(BorderStyle.DOTTED);
            headerCellStyle.setAlignment(HorizontalAlignment.LEFT);// 对齐
            headerCellStyle.setFillForegroundColor(HSSFColor.GREEN.index);
            headerCellStyle.setFillBackgroundColor(HSSFColor.GREEN.index);
            font.setColor(HSSFColor.WHITE.index);
            // 应用标题字体到标题样式
            headerCellStyle.setFont(font);
            //设置单元格文本形式
            DataFormat dataFormat =  wb.createDataFormat();
            headerCellStyle.setDataFormat(dataFormat.getFormat("@"));
        }
        return headerCellStyle;
    }
}
